﻿using System;
using System.Xml;

namespace NuGet.Enterprise.Server.Xml
{
    /// <summary>
    /// Base <see cref="XmlWriter"/> that can be use to create new writers by wrapping existing ones.
    /// </summary>
    public abstract class XmlWrappingWriter
        : XmlWriter
    {
        #region Fields

        private XmlWriter _baseWriter;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="XmlWrappingWriter"/> class.
        /// </summary>
        /// <param name="baseWriter">The base writer.</param>
        protected XmlWrappingWriter(XmlWriter baseWriter)
        {
            if (baseWriter == null)
            {
                throw new ArgumentNullException("baseWriter");
            }

            _baseWriter = baseWriter;
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// Gets or sets the base writer.
        /// </summary>
        /// <value>The base writer.</value>
        protected XmlWriter BaseWriter
        {
            get
            {
                return _baseWriter;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("BaseWriter");
                }

                _baseWriter = value;
            }
        }

        #endregion Properties

        #region Overrides

        /// <summary>
        /// When overridden in a derived class, closes this stream and the underlying stream.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// A call is made to write more output after Close has been called or the result of this call is an invalid XML document.
        /// </exception>
        public override void Close() { _baseWriter.Close(); }

        /// <summary>
        /// Releases the unmanaged resources used by the <see cref="T:System.Xml.XmlWriter"/> and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (WriteState != WriteState.Closed) Close();

            ((IDisposable)_baseWriter).Dispose();
        }

        /// <summary>
        /// When overridden in a derived class, flushes whatever is in the buffer to the underlying streams and also flushes the underlying stream.
        /// </summary>
        public override void Flush() { _baseWriter.Flush(); }

        /// <summary>
        /// When overridden in a derived class, returns the closest prefix defined in the current namespace scope for the namespace URI.
        /// </summary>
        /// <param name="ns">The namespace URI whose prefix you want to find.</param>
        /// <returns>
        /// The matching prefix or null if no matching namespace URI is found in the current scope.
        /// </returns>
        /// <exception cref="T:System.ArgumentException">
        /// 	<paramref name="ns"/> is either null or String.Empty.
        /// </exception>
        public override string LookupPrefix(string ns) { return _baseWriter.LookupPrefix(ns); }

        /// <summary>
        /// When overridden in a derived class, encodes the specified binary bytes as Base64 and writes out the resulting text.
        /// </summary>
        /// <param name="buffer">Byte array to encode.</param>
        /// <param name="index">The position in the buffer indicating the start of the bytes to write.</param>
        /// <param name="count">The number of bytes to write.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="buffer"/> is null.
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// The buffer length minus <paramref name="index"/> is less than <paramref name="count"/>.
        /// </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> or <paramref name="count"/> is less than zero.
        /// </exception>
        public override void WriteBase64(byte[] buffer, int index, int count) { _baseWriter.WriteBase64(buffer, index, count); }

        /// <summary>
        /// When overridden in a derived class, writes out a &lt;![CDATA[...]]&gt; block containing the specified text.
        /// </summary>
        /// <param name="text">The text to place inside the CDATA block.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The text would result in a non-well formed XML document.
        /// </exception>
        public override void WriteCData(string text) { _baseWriter.WriteCData(text); }

        /// <summary>
        /// When overridden in a derived class, forces the generation of a character entity for the specified Unicode character value.
        /// </summary>
        /// <param name="ch">The Unicode character for which to generate a character entity.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The character is in the surrogate pair character range, 0xd800 - 0xdfff.
        /// </exception>
        public override void WriteCharEntity(char ch) { _baseWriter.WriteCharEntity(ch); }

        /// <summary>
        /// When overridden in a derived class, writes text one buffer at a time.
        /// </summary>
        /// <param name="buffer">Character array containing the text to write.</param>
        /// <param name="index">The position in the buffer indicating the start of the text to write.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="buffer"/> is null.
        /// </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> or <paramref name="count"/> is less than zero.
        /// -or-
        /// The buffer length minus <paramref name="index"/> is less than <paramref name="count"/>; the call results in surrogate pair characters being split or an invalid surrogate pair being written.
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// The <paramref name="buffer"/> parameter value is not valid.
        /// </exception>
        public override void WriteChars(char[] buffer, int index, int count) { _baseWriter.WriteChars(buffer, index, count); }

        /// <summary>
        /// When overridden in a derived class, writes out a comment &lt;!--...--&gt; containing the specified text.
        /// </summary>
        /// <param name="text">Text to place inside the comment.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The text would result in a non-well formed XML document.
        /// </exception>
        public override void WriteComment(string text) { _baseWriter.WriteComment(text); }

        /// <summary>
        /// When overridden in a derived class, writes the DOCTYPE declaration with the specified name and optional attributes.
        /// </summary>
        /// <param name="name">The name of the DOCTYPE. This must be non-empty.</param>
        /// <param name="pubid">If non-null it also writes PUBLIC "pubid" "sysid" where <paramref name="pubid"/> and <paramref name="sysid"/> are replaced with the value of the given arguments.</param>
        /// <param name="sysid">If <paramref name="pubid"/> is null and <paramref name="sysid"/> is non-null it writes SYSTEM "sysid" where <paramref name="sysid"/> is replaced with the value of this argument.</param>
        /// <param name="subset">If non-null it writes [subset] where subset is replaced with the value of this argument.</param>
        /// <exception cref="T:System.InvalidOperationException">
        /// This method was called outside the prolog (after the root element).
        /// </exception>
        /// <exception cref="T:System.ArgumentException">
        /// The value for <paramref name="name"/> would result in invalid XML.
        /// </exception>
        public override void WriteDocType(string name, string pubid, string sysid, string subset) { _baseWriter.WriteDocType(name, pubid, sysid, subset); }

        /// <summary>
        /// When overridden in a derived class, closes the previous <see cref="M:System.Xml.XmlWriter.WriteStartAttribute(System.String,System.String)"/> call.
        /// </summary>
        public override void WriteEndAttribute() { _baseWriter.WriteEndAttribute(); }

        /// <summary>
        /// When overridden in a derived class, closes any open elements or attributes and puts the writer back in the Start state.
        /// </summary>
        /// <exception cref="T:System.ArgumentException">
        /// The XML document is invalid.
        /// </exception>
        public override void WriteEndDocument() { _baseWriter.WriteEndDocument(); }

        /// <summary>
        /// When overridden in a derived class, closes one element and pops the corresponding namespace scope.
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// This results in an invalid XML document.
        /// </exception>
        public override void WriteEndElement() { _baseWriter.WriteEndElement(); }

        /// <summary>
        /// When overridden in a derived class, writes out an entity reference as &amp;name;.
        /// </summary>
        /// <param name="name">The name of the entity reference.</param>
        /// <exception cref="T:System.ArgumentException">
        /// 	<paramref name="name"/> is either null or String.Empty.
        /// </exception>
        public override void WriteEntityRef(string name) { _baseWriter.WriteEntityRef(name); }

        /// <summary>
        /// When overridden in a derived class, closes one element and pops the corresponding namespace scope.
        /// </summary>
        public override void WriteFullEndElement() { _baseWriter.WriteFullEndElement(); }

        /// <summary>
        /// When overridden in a derived class, writes out a processing instruction with a space between the name and text as follows: &lt;?name text?&gt;.
        /// </summary>
        /// <param name="name">The name of the processing instruction.</param>
        /// <param name="text">The text to include in the processing instruction.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The text would result in a non-well formed XML document.
        /// <paramref name="name"/> is either null or String.Empty.
        /// This method is being used to create an XML declaration after <see cref="M:System.Xml.XmlWriter.WriteStartDocument"/> has already been called.
        /// </exception>
        public override void WriteProcessingInstruction(string name, string text) { _baseWriter.WriteProcessingInstruction(name, text); }

        /// <summary>
        /// When overridden in a derived class, writes raw markup manually from a string.
        /// </summary>
        /// <param name="data">String containing the text to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// 	<paramref name="data"/> is either null or String.Empty.
        /// </exception>
        public override void WriteRaw(string data) { _baseWriter.WriteRaw(data); }

        /// <summary>
        /// When overridden in a derived class, writes raw markup manually from a character buffer.
        /// </summary>
        /// <param name="buffer">Character array containing the text to write.</param>
        /// <param name="index">The position within the buffer indicating the start of the text to write.</param>
        /// <param name="count">The number of characters to write.</param>
        /// <exception cref="T:System.ArgumentNullException">
        /// 	<paramref name="buffer"/> is null.
        /// </exception>
        /// <exception cref="T:System.ArgumentOutOfRangeException">
        /// 	<paramref name="index"/> or <paramref name="count"/> is less than zero.
        /// -or-
        /// The buffer length minus <paramref name="index"/> is less than <paramref name="count"/>.
        /// </exception>
        public override void WriteRaw(char[] buffer, int index, int count) { _baseWriter.WriteRaw(buffer, index, count); }

        /// <summary>
        /// When overridden in a derived class, writes the start of an attribute with the specified prefix, local name, and namespace URI.
        /// </summary>
        /// <param name="prefix">The namespace prefix of the attribute.</param>
        /// <param name="localName">The local name of the attribute.</param>
        /// <param name="ns">The namespace URI for the attribute.</param>
        public override void WriteStartAttribute(string prefix, string localName, string ns) { _baseWriter.WriteStartAttribute(prefix, localName, ns); }

        /// <summary>
        /// When overridden in a derived class, writes the XML declaration with the version "1.0".
        /// </summary>
        /// <exception cref="T:System.InvalidOperationException">
        /// This is not the first write method called after the constructor.
        /// </exception>
        public override void WriteStartDocument() { _baseWriter.WriteStartDocument(); }

        /// <summary>
        /// When overridden in a derived class, writes the XML declaration with the version "1.0" and the standalone attribute.
        /// </summary>
        /// <param name="standalone">If true, it writes "standalone=yes"; if false, it writes "standalone=no".</param>
        /// <exception cref="T:System.InvalidOperationException">
        /// This is not the first write method called after the constructor.
        /// </exception>
        public override void WriteStartDocument(bool standalone) { _baseWriter.WriteStartDocument(standalone); }

        /// <summary>
        /// When overridden in a derived class, writes the specified start tag and associates it with the given namespace and prefix.
        /// </summary>
        /// <param name="prefix">The namespace prefix of the element.</param>
        /// <param name="localName">The local name of the element.</param>
        /// <param name="ns">The namespace URI to associate with the element.</param>
        /// <exception cref="T:System.InvalidOperationException">
        /// The writer is closed.
        /// </exception>
        public override void WriteStartElement(string prefix, string localName, string ns) { _baseWriter.WriteStartElement(prefix, localName, ns); }

        /// <summary>
        /// When overridden in a derived class, writes the given text content.
        /// </summary>
        /// <param name="text">The text to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The text string contains an invalid surrogate pair.
        /// </exception>
        public override void WriteString(string text) { _baseWriter.WriteString(text); }

        /// <summary>
        /// When overridden in a derived class, generates and writes the surrogate character entity for the surrogate character pair.
        /// </summary>
        /// <param name="lowChar">The low surrogate. This must be a value between 0xDC00 and 0xDFFF.</param>
        /// <param name="highChar">The high surrogate. This must be a value between 0xD800 and 0xDBFF.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid surrogate character pair was passed.
        /// </exception>
        public override void WriteSurrogateCharEntity(char lowChar, char highChar) { _baseWriter.WriteSurrogateCharEntity(lowChar, highChar); }

        /// <summary>
        /// Writes a <see cref="T:System.Boolean"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Boolean"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(bool value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.DateTime"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.DateTime"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(DateTime value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.Decimal"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Decimal"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(decimal value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.Double"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Double"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(double value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.Int32"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Int32"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(int value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.Int64"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.Int64"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(long value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes the object value.
        /// </summary>
        /// <param name="value">The object value to write.
        /// Note:
        /// With the release of the .NET Framework 3.5,
        /// this method accepts
        /// <see cref="T:System.DateTimeOffset"/> as a parameter.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        /// <exception cref="T:System.ArgumentNullException">
        /// The <paramref name="value"/> is null.
        /// </exception>
        /// <exception cref="T:System.InvalidOperationException">
        /// The writer is closed or in error state.
        /// </exception>
        public override void WriteValue(object value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a single-precision floating-point number.
        /// </summary>
        /// <param name="value">The single-precision floating-point number to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(float value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// Writes a <see cref="T:System.String"/> value.
        /// </summary>
        /// <param name="value">The <see cref="T:System.String"/> value to write.</param>
        /// <exception cref="T:System.ArgumentException">
        /// An invalid value was specified.
        /// </exception>
        public override void WriteValue(string value) { _baseWriter.WriteValue(value); }

        /// <summary>
        /// When overridden in a derived class, writes out the given white space.
        /// </summary>
        /// <param name="ws">The string of white space characters.</param>
        /// <exception cref="T:System.ArgumentException">
        /// The string contains non-white space characters.
        /// </exception>
        public override void WriteWhitespace(string ws) { _baseWriter.WriteWhitespace(ws); }

        /// <summary>
        /// Gets the <see cref="T:System.Xml.XmlWriterSettings"/> object used to create this <see cref="T:System.Xml.XmlWriter"/> instance.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The <see cref="T:System.Xml.XmlWriterSettings"/> object used to create this writer instance. If this writer was not created using the System.Xml.XmlWriter.Create method, this property returns null.
        /// </returns>
        public override XmlWriterSettings Settings
        {
            get { return _baseWriter.Settings; }
        }

        /// <summary>
        /// When overridden in a derived class, gets the state of the writer.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// One of the <see cref="T:System.Xml.WriteState"/> values.
        /// </returns>
        public override WriteState WriteState
        {
            get { return _baseWriter.WriteState; }
        }

        /// <summary>
        /// When overridden in a derived class, gets the current xml:lang scope.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The current xml:lang scope.
        /// </returns>
        public override string XmlLang
        {
            get { return _baseWriter.XmlLang; }
        }

        /// <summary>
        /// When overridden in a derived class, gets an <see cref="T:System.Xml.XmlSpace"/> representing the current xml:space scope.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// An XmlSpace representing the current xml:space scope.
        /// Value
        /// Meaning
        /// None
        /// This is the default if no xml:space scope exists.
        /// Default
        /// The current scope is xml:space="default".
        /// Preserve
        /// The current scope is xml:space="preserve".
        /// </returns>
        public override XmlSpace XmlSpace
        {
            get { return _baseWriter.XmlSpace; }
        }

        #endregion Overrides
    }
}
